///////////////////////////////////////////////////////////////////////////////////////
//
//	DoD Weapon Jam
//		- Version 2.0
//		- 01.29.2008
//		- diamond-optic
//
//////////////////////////////////////////////////////////////////////////////////
//
// Credits:
//
//	- Wilson [29th ID] (pdata offsets as well as a ton of other help)
//
//////////////////////////////////////////////////////////////////////////////////
//
// Information:
//
//	- Weapons will randomly jam and the client will have to press
//	  their use key to clear the chamber (or reload depending on setting)
//
//	- Sometimes clearing the chamber fails, requiring multiple attempts
//	- Chance of weapon jamming permanently
//	- Specific weapon stays jammed even after dropping it
//	- Enable/Disable losing 1 round in the clip when clearing the chamber
//	- Weapons will not jam on a full clip (so you dont spawn with a jammed weapon)
//
//////////////////////////////////////////////////////////////////////////////////
//
// CVARs:
//
//	dod_weaponjam "1"		//Turn plugin on(1)/off(0)
//
//	dod_weaponjam_msgstyle "1"	//Message Style Setting
//						//1 = HUD Messages
//						//2 = Chat Messages
//						//3 = Both HUD & Chat Messages
//
//	dod_weaponjam_chance "800"	//Chance of weapon jamming for each shot (1 in ### chance)
//
//	dod_weaponjam_reload "1"	//Reloading clears jammed weapons (on(1)/off(0))
//	dod_weaponjam_ammo "1"		//Clearing chamber subtracts 1 round of ammo (on(1)/off(0))
//	
//	dod_weaponjam_perm "50"		//Chance of weapon jam to be permanent (0 = no perm jam)
//	dod_weaponjam_fail "4"		//Chance of clearing chamber failing (0 = always clears 1st time, 1 in ### chance)
//
//////////////////////////////////////////////////////////////////////////////////
//
// Extra:
//
//	- The FULL_PRECACHE define sets whether the sound files are precached or not 
//		* If you find that the sounds dont work, enable this
//		* If you get 'file not precached' errors, enable this
//
//////////////////////////////////////////////////////////////////////////////////
//
// Change Log:
//
//	- 07.23.07 - Version 1.0
//		Initial Release
//
//	- 09.12.07 - Version 1.1
//		Adjusted default jam chances just slightly
//		Stopped 'jammed' sounds from playing after round end
//		Added CVAR to control message style
//		Fixed jam sound from overlapping itself
//
//	- 01.29.08 - Version 2.0
//		Huge Rewrite, too many changes to list
//
///////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////
// Module Include
//
#include <amxmodx>
#include <amxmisc>
#include <fakemeta>
#include <dodfun>
#include <dodx>

/////////////////////////////////////////////////
// Version Variable
//
#define VERSION "2.0"
#define SVERSION "v2.0 - by diamond-optic (www.AvaMods.com)"

/////////////////////////////////////////////////
// PData Offsets
//
#define OFFSET_WPN_PROF 103	//Weapon Primary Attack ROF
#define OFFSET_WPN_CLIP 108	//Weapon Clip Ammo
#define OFFSET_WPN_ID 91	//Weapon ID
#define OFFSET_LINUX 4		//Linux Offset

/////////////////////////////////////////////////
// FULL PRECACHE   (1=ON/0=OFF)
//
// Enable this if you find that some of
// the sounds dont play or they return
// precache errors.
// 
#define FULL_PRECACHE 0

/////////////////////////////////////////////////
// iuser Usage
//
// This plugin uses two seperate
// iuser slots on weapon entities
//
// iuser3 >> 1=reloading
// iuser4 >> 1=jammed 2=permanently jammed
//

//////////////////////////////////////////////////
// File Variables
//
new fileNames[3][] =
{
	"weapons/weaponempty.wav",
	"weapons/mgbolt.wav",
	"weapons/clampdown.wav"
}

enum
{
	empty,
	clear,
	failed
}

/////////////////////////////////////////////////
// PCVARs
//
new p_plugin, p_chance, p_perm, p_msg , p_reload, p_fail, p_ammo

/////////////////////////////////////////////////
// Global Variables
//
new bool:g_round_restart = false
new Float:jamTime[33]

/////////////////////////////////////////////////
// Plugin Initialization
//
public plugin_init()
{
	register_plugin("DoD Weapon Jam",VERSION,"AMXX DoD Team")
	register_cvar("dod_weaponjam_stats",SVERSION,FCVAR_SERVER|FCVAR_SPONLY)

	//Register CVARs
	p_plugin = register_cvar("dod_weaponjam", "1")
	p_chance = register_cvar("dod_weaponjam_chance", "800") 
	p_perm = register_cvar("dod_weaponjam_perm","50")
	p_reload = register_cvar("dod_weaponjam_reload", "1")
	p_ammo = register_cvar("dod_weaponjam_ammo","1")
	p_fail = register_cvar("dod_weaponjam_fail","4")
	p_msg = register_cvar("dod_weaponjam_msgstyle","1")

	//Register Forwards
	register_forward(FM_PlayerPreThink, "jam_prethink")

	//Register Events
	register_event("ReloadDone", "reload_done", "be") 
	register_event("CurWeapon","cur_weapon","be","1=1","2!=0","2!=1","2!=2","2!=13","2!=14","2!=15","2!=16","2!=19","2!=29","2!=30","2!=31","2!=34","3>0")	
	
	// Register Event Hooks	
	register_event("RoundState", "round_message", "a", "1=1", "1=3", "1=4", "1=5")
}

#if FULL_PRECACHE == 1 

/////////////////////////////////////////////////
// File Precache
//
public plugin_precache() 
{
	// DoD already precaches these???
	precache_sound(fileNames[empty])		// empty/jammed click sound
	precache_sound(fileNames[clear])		// clear chamber sound (success)
	precache_sound(fileNames[failed])		// clear chamber sound (failed)
}

#endif

/////////////////////////////////////////////////
// CurWeapon Hook - Sets Jammed
//
public cur_weapon(id)
{
	if(get_pcvar_num(p_plugin) && is_user_alive(id) && is_user_connected(id) && !is_user_bot(id))
		{
		new wpnid = dod_get_weapon_ent(id)
		new is_jammed = pev(wpnid,pev_iuser4)
		
		if(wpnid && pev_valid(wpnid))
			{
			set_pev(wpnid,pev_iuser3,0)
			
			if(is_jammed)
				set_pdata_float(wpnid,OFFSET_WPN_PROF,100.0,OFFSET_LINUX)	
			else if(is_clip_notfull(id))
				{
				if(random_num(1,get_pcvar_num(p_chance)) == 1)
					{
					new perm = get_pcvar_num(p_perm)
					
					if(perm && random_num(1,perm) == 1)
						set_pev(wpnid,pev_iuser4,2)
					else
						set_pev(wpnid,pev_iuser4,1)
					}
				}
			}	
		}
}


/////////////////////////////////////////////////
// Reload Complete - unjam
//
public reload_done(id)
{ 
	if(get_pcvar_num(p_plugin) && is_user_alive(id) && is_user_connected(id) && !is_user_bot(id))
		{
		new wpnid = dod_get_weapon_ent(id)
		new is_jammed = pev(wpnid,pev_iuser4)
			
		if(wpnid && pev_valid(wpnid))
			{
			set_pev(wpnid,pev_iuser3,0)
			
			if(get_pcvar_num(p_reload) && is_jammed == 1)
				{
				set_pdata_float(wpnid,OFFSET_WPN_PROF,0.0,OFFSET_LINUX)
				set_pev(wpnid,pev_iuser4,0)
				jamTime[id] = 0.0
				}
			else if(is_jammed)
				set_pdata_float(wpnid,OFFSET_WPN_PROF,100.0,OFFSET_LINUX)
				
			}
		}
}


/////////////////////////////////////////////////
// Prethink
//
public jam_prethink(id)
{
	if(get_pcvar_num(p_plugin) && is_user_alive(id) && is_user_connected(id) && !is_user_bot(id) && !g_round_restart)
		{
		new buttons = pev(id,pev_button)
			
		if(buttons & IN_ATTACK)
			{
			new wpnid = dod_get_weapon_ent(id)
			new is_jammed = pev(wpnid,pev_iuser4)
			new is_reload = pev(wpnid,pev_iuser3)
			
			new Float:gametime = get_gametime()
	
			if(wpnid && pev_valid(wpnid) && is_jammed && !is_reload && jamTime[id]+0.3 < gametime)
				{
				set_pdata_float(wpnid,OFFSET_WPN_PROF,100.0,OFFSET_LINUX)
								
				if(!jamTime[id])
					jamTime[id] = gametime-0.2
				else
					{
					set_pev(id,pev_button,buttons & ~IN_ATTACK)
					client_cmd(id,"-attack")
					
					jamTime[id] = gametime
					}
					
				emit_sound(wpnid,CHAN_WEAPON,fileNames[empty],1.0,ATTN_NORM,0,PITCH_NORM)
				
				new msgStyle = get_pcvar_num(p_msg)
				
				if(is_jammed == 2)
					{
					if(msgStyle == 1 || msgStyle == 3)
						{
						set_hudmessage(192, 25, 25, 0.1, 0.15, 1, 0.4, 2.0, 0.5, 2.0, 3)
						show_hudmessage(id, "Your Weapon Is Permanently Jammed!!^nYou Can NOT Fix This Weapon..")
						}
					if(msgStyle == 2 || msgStyle == 3)
						client_print(id,print_chat,"*** Your Weapon Is Permanently Jammed!! You Can NOT Fix This Weapon..")
					}
				else
					{
					if(get_pcvar_num(p_reload) && is_clip_notfull(id) == 1)
						{
						if(msgStyle == 1 || msgStyle == 3)
							{
							set_hudmessage(192, 25, 25, 0.1, 0.15, 1, 0.4, 2.0, 0.5, 2.0, 3)
							show_hudmessage(id, "Your Weapon Is Jammed!!^nPress Your +USE Key To Clear The Chamber^nor Reload Your Weapon...")
							}
						if(msgStyle == 2 || msgStyle == 3)
							client_print(id,print_chat,"*** Your Weapon Is Jammed!! Press Your +USE Key To Clear The Chamber or Reload Your Weapon..")
						}
					else
						{
						if(msgStyle == 1 || msgStyle == 3)
							{
							set_hudmessage(192, 25, 25, 0.1, 0.15, 1, 0.4, 2.0, 0.5, 2.0, 3)
							show_hudmessage(id, "Your Weapon Is Jammed!!^nPress Your +USE Key To Clear The Chamber")
							}
						if(msgStyle == 2 || msgStyle == 3)
							client_print(id,print_chat,"*** Your Weapon Is Jammed!! Press Your +USE Key To Clear The Chamber..")
						}
					}				
				}
			}
		else if(buttons & IN_USE)
			{
			new wpnid = dod_get_weapon_ent(id)
			new is_jammed = pev(wpnid,pev_iuser4)
			new is_reload = pev(wpnid,pev_iuser3)
			
			new Float:gametime = get_gametime()
			
			if(wpnid && pev_valid(wpnid) && is_jammed && !is_reload && jamTime[id]+0.3 < gametime)
				{
				set_pev(id,pev_button,buttons & ~IN_USE)
				client_cmd(id,"-use")
				
				jamTime[id] = gametime
							
				new msgStyle = get_pcvar_num(p_msg)
							
				if(is_jammed == 1)
					{					
					new fail = get_pcvar_num(p_fail)
					
					if(fail && random_num(1,fail) == 1)
						{
						emit_sound(wpnid,CHAN_WEAPON,fileNames[failed],1.0,ATTN_NORM,0,PITCH_NORM)
							
						// show messages
						if(msgStyle == 1 || msgStyle == 3)
							{
							set_hudmessage(192, 25, 25, 0.1, 0.25, 0, 0.4, 1.5, 0.5, 2.0, 3)
							show_hudmessage(id,"Chamber NOT Cleared!^nTry To Clear It Again..")
							}
						if(msgStyle == 2 || msgStyle == 3)
							client_print(id,print_chat,"*** Chamber NOT Cleared! Try To Clear It Again..")
						}
					else
						{
						set_pev(wpnid,pev_iuser4,0)
						set_pdata_float(wpnid,OFFSET_WPN_PROF,0.0,OFFSET_LINUX)
						
						jamTime[id] = 0.0

						if(get_pcvar_num(p_ammo))
							{
							new clip = get_pdata_int(wpnid,OFFSET_WPN_CLIP,OFFSET_LINUX)
						
							if(clip)				
								set_pdata_int(wpnid,OFFSET_WPN_CLIP,clip - 1,OFFSET_LINUX)
							}
							
						emit_sound(wpnid,CHAN_WEAPON,fileNames[clear],1.0,ATTN_NORM,0,PITCH_NORM)
				
						// show messages
						if(msgStyle == 1 || msgStyle == 3)
							{
							set_hudmessage(25, 25, 192, 0.1, 0.25, 0, 0.4, 1.5, 0.5, 2.0, 3)
							show_hudmessage(id,"Chamber Cleared!^nYour Weapon Is Now Unjammed..")
							}
						if(msgStyle == 2 || msgStyle == 3)
							client_print(id,print_chat,"*** Chamber Cleared! Your Weapon Is Now Unjammed..")
						}
					}
				else
					{
					emit_sound(wpnid,CHAN_WEAPON,fileNames[failed],1.0,ATTN_NORM,0,PITCH_NORM)
						
					// show message
					if(msgStyle == 1 || msgStyle == 3)
						{
						set_hudmessage(25, 192, 25, 0.1, 0.15, 1, 0.4, 2.0, 0.5, 2.0, 3)
						show_hudmessage(id, "Your Weapon Is Permanently Jammed!!^nYou Can NOT Fix This Weapon..")
						}
					if(msgStyle == 2 || msgStyle == 3)
						client_print(id,print_chat,"*** Your Weapon Is Permanently Jammed!! You Can NOT Fix This Weapon..")
					}
				}
			}
		else if(buttons & IN_RELOAD)
			{
			new wpnid = dod_get_weapon_ent(id)
			new is_jammed = pev(wpnid,pev_iuser4)
			
			if(wpnid && pev_valid(wpnid) && is_jammed)				
				if(is_clip_notfull(id) == 1)
					set_pev(wpnid,pev_iuser3,1)
			}
		else if(buttons & IN_ATTACK2)
			{
			new wpnid = dod_get_weapon_ent(id)
			new is_jammed = pev(wpnid,pev_iuser4)
			
			if(wpnid && pev_valid(wpnid) && is_jammed)
				set_pdata_float(wpnid,OFFSET_WPN_PROF,100.0,OFFSET_LINUX)
			}
		}
		
	return FMRES_IGNORED
}


///////////////////////////////////////////////////////////////////////////////////////
// hook the round message and handle
//
public round_message() 
{
	if(read_data(1) == 1)
		g_round_restart = false
	else
		g_round_restart = true
}


/////////////////////////////////////////////////
// Get Current Weapon ID Stock
//
stock dod_get_weapon_ent(id)
{
	new ent = -1,entid
	new wpnid = dod_get_user_weapon(id)

	// Get User Origin
	new Float:origin[3]
	pev(id,pev_origin,origin)
	
	switch(wpnid)
		{
		case 35: wpnid = 25
		case 32: wpnid = 23
		}
	
	// Find Weapon
	while((ent = engfunc(EngFunc_FindEntityInSphere,ent,origin,Float:1.0)) != 0)
		{
		if(pev_valid(ent))
			{
			if(wpnid)
				{
				entid = get_pdata_int(ent,OFFSET_WPN_ID,OFFSET_LINUX)
				
				if(wpnid == entid) return ent
				}
			}
		}
		
	return 0
}



/////////////////////////////////////////////////
// Is Clip NOT Full Stock
//
// returns: 0=clip is full, 1=clip is not full, 2=clip is not full, but its garand
stock is_clip_notfull(id)
{
	new ammo, clip, weapon = dod_get_user_weapon(id,clip,ammo)
			
	switch(weapon)
		{
		//axis
		case DODW_LUGER: { if(clip != 8) return 1; }
		case DODW_KAR: { if(clip != 5) return 1; }
		case DODW_K43: { if(clip != 10) return 1; }
		case DODW_MP40: { if(clip != 30) return 1; }
		case DODW_STG44: { if(clip != 30) return 1; }
		case DODW_FG42: { if(clip != 20) return 1; }
		case DODW_SCOPED_FG42: { if(clip != 20) return 1; }
		case DODW_SCOPED_KAR: { if(clip != 5) return 1; }
		case DODW_MG34: { if(clip != 75) return 1; }
		case DODW_MG42: { if(clip != 250) return 1; }
		//americans
		case DODW_COLT:	{ if(clip != 7) return 1; }
		case DODW_GARAND: { if(clip) return 2; }
		case DODW_FOLDING_CARBINE: { if(clip != 15) return 1; }
		
		case DODW_M1_CARBINE: { if(clip != 15) return 1; }
		case DODW_THOMPSON: { if(clip != 30) return 1; }
		case DODW_GREASEGUN: { if(clip != 30) return 1; }
		case DODW_SPRINGFIELD: { if(clip != 5) return 1; }
		case DODW_BAR: { if(clip != 20) return 1; }
		case DODW_30_CAL: { if(clip != 150) return 1; }
		//british
		case DODW_WEBLEY: { if(clip != 6) return 1; }
		case DODW_ENFIELD: { if(clip != 10) return 1; }
		case DODW_STEN: { if(clip != 30) return 1; }
		case DODW_SCOPED_ENFIELD: { if(clip != 10) return 1; }
		case DODW_BREN: { if(clip != 30) return 1; }
		}
	
	return 0	
}
